(ns intro.visualization
(:require [scicloj.kind-clerk.api :as kind-clerk]
[tablecloth.api :as tc]
[aerial.hanami.common :as hc]
[aerial.hanami.templates :as ht]
[scicloj.noj.v1.vis.hanami.templates :as vht]
[scicloj.noj.v1.vis :as vis]
[scicloj.noj.v1.stats :as stats]
[tech.v3.datatype :as dtype]
[tech.v3.datatype.functional :as fun]
[scicloj.kindly.v3.api :as kindly]
[scicloj.kindly.v3.kind :as kind]
[hiccup.core :as hiccup]
[clojure2d.color :as color]))(-> "Hello, Noj.
"
vis/raw-html)(-> [:svg {:height 210
:width 500}
[:line {:x1 0
:y1 0
:x2 200
:y2 200
:style "stroke:rgb(255,0,0);stroke-width:2"}]]
hiccup/html
vis/raw-html)Noj offers a few convenience functions to make Hanami plotting work smoothly with Tablecloth and Kindly.
(def mtcars
(-> "data/mtcars.csv"
(tc/dataset {:key-fn keyword})))(def iris
(-> "data/iris.csv"
(tc/dataset {:key-fn keyword})))(def random-walk
(let [n 20]
(-> {:x (range n)
:y (->> (repeatedly n #(- (rand) 0.5))
(reductions +))}
tc/dataset)))We can plot a Tablecloth datasete using a Hanami template:
(-> random-walk
(vis/hanami-plot ht/point-chart
{:MSIZE 200}))Let us look inside the resulting vega-lite space. We can see the dataset is included as CSV:
(-> random-walk
(vis/hanami-plot ht/point-chart
{:MSIZE 200})
kind/pprint){:encoding
{:y {:field "y", :type "quantitative"},
:x {:field "x", :type "quantitative"}},
:mark {:type "circle", :size 200, :tooltip true},
:width 400,
:background "floralwhite",
:height 300,
:data
{:values
"x,y\n0,0.46278344327931786\n1,0.7225300428080409\n2,0.6825960991459601\n3,1.1049084925640287\n4,1.5905499030440238\n5,1.1175203576814434\n6,1.1464975887685016\n7,1.0836373417840375\n8,1.0564477984442235\n9,1.5542711767827888\n10,1.1411397794537894\n11,0.8097630170779119\n12,0.6711656092860713\n13,0.2685734593897352\n14,0.5441913226772874\n15,0.08645249109930675\n16,0.41432882437060037\n17,0.17021470305698538\n18,-0.22806651697229863\n19,-0.05236195858138093\n",
:format {:type "csv"}}}
The scicloj.noj.v1.vis.hanami.templates namespace add Hanami templates to Hanami's own collection.
(-> mtcars
(vis/hanami-plot vht/boxplot-chart
{:X :gear
:XTYPE :nominal
:Y :mpg}))(-> random-walk
(vis/hanami-layers
{:TITLE "points and a line"}
[(vis/hanami-plot nil
ht/point-chart
{:MSIZE 400})
(vis/hanami-plot nil
ht/line-chart
{:MSIZE 4
:MCOLOR "brown"})]))(-> random-walk
(vis/hanami-vconcat
{}
[(vis/hanami-plot nil
ht/point-chart
{:MSIZE 400
:HEIGHT 100
:WIDTH 100})
(vis/hanami-plot nil
ht/line-chart
{:MSIZE 4
:MCOLOR "brown"
:HEIGHT 100
:WIDTH 100})]))(-> random-walk
(vis/hanami-hconcat
{}
[(vis/hanami-plot nil
ht/point-chart
{:MSIZE 400
:HEIGHT 100
:WIDTH 100})
(vis/hanami-plot nil
ht/line-chart
{:MSIZE 4
:MCOLOR "brown"
:HEIGHT 100
:WIDTH 100})]))(-> mtcars
(stats/add-predictions :mpg [:wt]
{:model-type :smile.regression/ordinary-least-square})
(vis/hanami-layers {}
[(vis/hanami-plot nil
ht/point-chart
{:X :wt
:Y :mpg
:MSIZE 200
:HEIGHT 200
:WIDTH 200})
(vis/hanami-plot nil
ht/line-chart
{:X :wt
:Y :mpg-prediction
:MSIZE 5
:MCOLOR "purple"
:YTITLE :mpg})]))(-> iris
(vis/hanami-histogram :sepal-width
{:nbins 10}))The following is inspired by the example at Plotnine's main page. Note how we add regression lines here.
(let [pallete (->> :accent
color/palette
(mapv color/format-hex))]
(-> mtcars
(tc/group-by :gear {:result-type :as-map})
(->> (sort-by key)
(map-indexed
(fn [i [group-name ds]]
(-> ds
(stats/add-predictions :mpg [:wt]
{:model-type :smile.regression/ordinary-least-square})
(vis/hanami-layers {:TITLE (str "grear=" group-name)}
[(vis/hanami-plot nil
ht/point-chart
{:X :wt
:Y :mpg
:MSIZE 200
:MCOLOR (pallete i)
:HEIGHT 200
:WIDTH 200})
(vis/hanami-plot nil
ht/line-chart
{:X :wt
:Y :mpg-prediction
:MSIZE 5
:MCOLOR (pallete i)
:YTITLE :mpg})]
))))
(vis/hanami-hconcat nil {}))))(let [pallete (->> :accent
color/palette
(mapv color/format-hex))]
(-> iris
(tc/group-by :species {:result-type :as-map})
(->> (sort-by key)
(map-indexed
(fn [i [group-name ds]]
(-> ds
(vis/hanami-histogram :sepal-width
{:nbins 10}))))
(vis/hanami-vconcat nil {})))):bye:bye